﻿using System;
using System.Threading;
using System.Net.Sockets;
using System.Net;

namespace ServerFrame
{
	public class Server
	{
		int port;//连接端口
		int maxConn;//最大连接数
		Semaphore maxConn_se;//连接信号量
		Socket svrSocket;
		int waitConn;//连接满，可以挂起的连接数
		 
		public AbsMessageCenter center;

		ObjPool<MyToken> tokenPool;
		/// <summary>
		/// 初始化服务
		/// </summary>
		/// <param name="p">端口</param>
		/// <param name="conn">最大连接数</param>
		/// <param name="wait_num">挂起连接数</param>
		public Server (int p,int conn,int wait_num=10)
		{
			port = p;
			maxConn = conn;
			maxConn_se = new Semaphore (maxConn, maxConn);
			waitConn = wait_num;

			Init ();
		}

		/// <summary>
		/// 初始化函数
		/// </summary>
		void Init(){

			tokenPool = new ObjPool<MyToken> (maxConn);
			//初始化token(自定义),并把他压入对象池
			for (int i = 0; i < maxConn; i++) {
				MyToken token = new MyToken ();
				token.read_args.Completed += new EventHandler<SocketAsyncEventArgs> (IO_Completed);
				token.write_args.Completed += new EventHandler<SocketAsyncEventArgs> (IO_Completed);

				tokenPool.Push (token);
			}

		}


		public void Start(){

			try{
				//新建套接字
				svrSocket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
				svrSocket.Bind (new IPEndPoint (IPAddress.Any, port));
				svrSocket.Listen (waitConn);
				Console.WriteLine ("start accept");
				StartAccept (null);
			}catch(Exception e){
				Console.WriteLine (e);
			}

		}

		void StartAccept(SocketAsyncEventArgs e){
			//如果e为空，刚开始执行，e无连接，为e绑定完成事件
			if (e == null) {
				e = new SocketAsyncEventArgs ();
				e.Completed += new EventHandler<SocketAsyncEventArgs> (Accept_Completed);
			} else {
				e.AcceptSocket = null;//如果不为空，证明e已经监听了一个连接，把连接清空，等待一个新的连接
			}

			//开始异步监听
			maxConn_se.WaitOne();//信号量减一
			bool result= svrSocket.AcceptAsync (e);

			//判断操作是否被挂起
			if(!result){
				//没有挂起，说明立即执行完毕,执行对应的监听处理操作
				ProcessAccept(e);

			}//若挂起，等待连接，然后会执行Accept_Completed

		}

		void Accept_Completed(object sender, SocketAsyncEventArgs e){
			//执行对应的监听处理操作
			ProcessAccept(e);
		}


		void ProcessAccept(SocketAsyncEventArgs e){
			//从对象池取出读写 异步操作（读(接收异步操作)）
			MyToken token=tokenPool.Pop();

			token.socket = e.AcceptSocket;

			//通知上层应用，有客户端连接
			center.OnClientConnected(token);

			//开始异步接收操作
			bool result= token.socket.ReceiveAsync(token.read_args);

			if (!result) {
				ProcessReceive (token.read_args);
			}

			//循环利用e
			StartAccept (e);
		}



		void IO_Completed(object sender, SocketAsyncEventArgs e)
		{
			// determine which type of operation just completed and call the associated handler
			switch (e.LastOperation)
			{
			case SocketAsyncOperation.Receive:
				ProcessReceive(e);
				break;
			case SocketAsyncOperation.Send:
				//ProcessSend(e);
				break;
			default:
				throw new ArgumentException("The last operation completed on the socket was not a receive or send");
			}       

		}


		void ProcessReceive(SocketAsyncEventArgs e){
			//取出token
			MyToken token=(MyToken)e.UserToken;

			//读取socket 接收到的字节数，存起来
			if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
			{
				//接收的数据就在 e.BytesTransferred
				//调用token中的接收方法，开始读取处理数据
			}
			else
			{
				CloseClientSocket(token,"客户端断开连接");
			}

		}

		void CloseClientSocket(MyToken token,string error){
			

			//通知上层，客户端断开连接，清空token数据，放入对象池中
			//关闭token时，外部不应继续调用，上锁
			lock (token) {
				center.OnClientClose (token, error);

				token.Close ();
				tokenPool.Push (token);
				maxConn_se.Release ();
			}
		}
	}
}

